<?php if(! defined('HAS_POWER') ) exit('无权访问!');
/**
==============================================================================
 * Class Controller GracePHP的内置控制器基类
 * @author 肖永标
 * @date 2014-11-30
==============================================================================
 */
class Controller {

    /** 
     *  控制器基类构造函数
     */
    public function __construct()
    {
        if(method_exists($this, '_init'))
            $this->_init();
            
        $this->_autoLoadComponent();
    }

    /** 渲染加载模板
     * @param string $file 模板文件
     * @param array $data 渲染的数据
     * @throws Exception
     */
    public function render($file, $data=array())
    {
        $controller = strtolower(substr(UrlComponent::getController(), 0, -10));
        $path = CURRENT_MODULE . "views/$controller/$file.php";

        if(!file_exists($path))
            throw new Exception('视图文件[' . $path . ']不存在!');

        // 解析数组为变量
        extract($data);

        if(Config::getItem('htmlCache.enable'))
            $this->_htmlCache($path);
        else
            require_once $path;
    }


    /** html静态缓存
     *  @param string $path 需要缓存的php文件的路径
     */
    private function _cache($path)
    {
        $cacheDir = CURRENT_MODULE . 'cache/';
        $cacheExpire = Config::getItem('htmlCache.expired');
        $cacheFile = $cacheDir . md5("$path") . '.html';

        if(file_exists($cacheFile) && time() - filemtime($cacheFile) < $cacheExpire)
        {
            require_once $cacheFile;
            exit;
        }
        else
        {
            ob_start();

            require_once $path;

            $content = ob_get_contents();

            if(!is_dir($cacheDir))
                mkdir($cacheDir, 0777, true);
            file_put_contents($cacheFile, $content);

            ob_end_flush();
        }
    }


    /** 获取组件类
     * @param string $class 组件类的前缀名称
     * @param bool $static 组件类是否是单例的
     * @param string $alias 组件别名
     * @throws Exception
     */
    protected function loadComponent($class, $static=false, $alias='')
    {
        static $_component = array();

        $fullClass = ucfirst($class) . 'Component';

        $field = empty($alias) ? strtolower($class) : $alias;

        if(property_exists($this, $field))
            throw new Exception($field . '组件属性名称重复');

        if($static === false)
        {
            if(!isset($_component[$class]))
                $_component[$class] = new $fullClass();

            if(!$_component[$class]->allowLoad())
                throw new Exception($fullClass . '不能直接执行加载!');
            else
                $this->$field = $_component[$class];
        }
        else
        {
            if(!isset($_component[$class]))
                $_component[$class] = $fullClass::getIns();

            if(!$_component[$class]->allowLoad())
                throw new Exception($fullClass . '不能直接执行加载!');
            else
                $this->$field = $_component[$class];
        }
    }


    /** 加载一个模型实例
     * @param string $model 模型的名称
     * @return mixed
     */
    public function loadModel($model)
    {
        static $_model  = array();

        if(strpos($model, '://') === false)
        {
            $fullModel = ucfirst($model) . 'Model';
            require_once(Config::getItem('application') . MYAPP . 'model/' . $fullModel . '.class.php');
        }
        else
        {
            $temp = explode('://', $model);
            $fullModel = ucfirst($temp[1]) . 'Model';
            require_once(Config::getItem('application') . $temp[0] . '/model/' . $fullModel .'.class.php');
            $model = $temp[0] . '-' . $temp[1];
        }

        if(!isset($_model[$model]))
            $_model[$model] = new $fullModel();

        return $_model[$model];
    }


    /** 加载第三方扩展
     * @param string $class 类名字
     * @param string $suffix 文件后缀
     * @return mixed
     */
    public function loadExtend($class, $suffix = '.class.php')
    {
        require_once(EXTEND . '/' . $class . $suffix);
    }


    public function loadAssets($filename)
    {
        return Config::getItem('application'). 'resource/' . $filename;
    }

    /** 自动加载组件类
     * @return object
     * @throws Exception
     */
    private function _autoLoadComponent()
    {
        // 系统默认加载
        $this->loadComponent('input');
        $this->loadComponent('output');

        static $_component = array();

        // 加载配置项的组件类
        $auto = Config::getItem('autoLoadComponent');

        foreach($auto as $k=>$load)
        {
            $class = $load['class'];
            $attr = strtolower(substr($class, 0, -9));
            
            $field = array_key_exists('alias', $load) ? $load['alias'] : $attr;
            
            if($load['static'] == true)
            {
                if(!isset($_component[$class]))
                    $_component[$class] = $class::getIns();

                if(!$_component[$class]->allowLoad())
                    throw new Exception($class . '不能直接执行加载!');
                else
                    $this->$field = $_component[$class];
            }
            else
            {
                if(!isset($_component[$class]))
                    $_component[$class] = new $load['class']();

                if(!$_component[$class]->allowLoad())
                    throw new Exception($class . '不能直接执行加载!');
                else
                    $this->$field = $_component[$class];
            }
        }
    }

    /** html静态缓存
     *  @param string $path 需要缓存的php文件的路径
     */
    private function _htmlCache($path)
    {
        $cacheDir = CURRENT_MODULE . 'cache/';
        $cacheExpire = Config::getItem('htmlCache.expired');
        $cacheFile = $cacheDir . md5($path) . '.html';

        if(file_exists($cacheFile) && time() - filemtime($cacheFile) < $cacheExpire)
        {
            require_once $cacheFile;
            exit;
        }
        else
        {
            ob_start();

            require_once $path;

            $content = ob_get_contents();

            if(!is_dir($cacheDir))
                mkdir($cacheDir, 0777, true);
            file_put_contents($cacheFile, $content);

            ob_end_flush();
        }
    }
}